package com.chinairi.mall.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.chinairi.common.utils.Md5Util;
import com.chinairi.common.utils.RedisUtil;
import com.chinairi.common.utils.ResponseUtil;
import com.chinairi.common.utils.UserSession;
import com.chinairi.mall.config.ValidationResult;
import com.chinairi.mall.config.ValidatorImpl;
import com.chinairi.mall.controller.viewobject.UserRegisterVO;
import com.chinairi.mall.dao.*;
import com.chinairi.mall.error.BusinessException;
import com.chinairi.mall.error.EmBusinessError;
import com.chinairi.mall.model.*;
import com.chinairi.mall.service.ISysUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chinairi.mall.service.modelobject.CiccLabelMO;
import com.chinairi.mall.service.modelobject.NewUserMO;
import com.chinairi.mall.service.modelobject.UserInfoToRedisMO;
import com.chinairi.mall.util.*;
import com.chinairi.sms.api.utils.SmsSendUtil;
import com.thoughtworks.xstream.core.util.Base64Encoder;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.*;

/**
 * <p>
 * 员工基本信息(如果客户已有人力资源的用户信息表，则使用客户提供的表，不用该表) 服务实现类
 * </p>
 *
 * @author 董志涵
 * @since 2020-08-17
 */
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {

    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private SysUserLoginMapper sysUserLoginMapper;
    @Autowired
    private ValidatorImpl validator;
    @Autowired
    private UserCompanyInfoServiceImpl userCompanyInfoService;
    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private UserCompanyRelaMapper userCompanyRelaMapper;

    public void putRedis() {
        redisUtil.del("userInfoMap");
        List<UserInfoToRedisMO> userInfoToRedisMoList = sysUserMapper.getUserInfoToRedis();
        Map<String, Object> userInfoMap = new HashMap<>(userInfoToRedisMoList.size());
        for (UserInfoToRedisMO userInfoToRedisMo : userInfoToRedisMoList) {
            userInfoMap.put(userInfoToRedisMo.getUserId(), userInfoToRedisMo);
        }
        redisUtil.hmset("userInfoMap", userInfoMap, 86500);
    }


    /**
     * 更新用户信息
     *
     * @param userInfoToRedisMo 用户信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSysUserInfo(UserInfoToRedisMO userInfoToRedisMo) {
        SysUser sysUser = new SysUser();
        SysUserLogin sysUserLogin = new SysUserLogin();
        BeanUtils.copyProperties(userInfoToRedisMo, sysUser);
        BeanUtils.copyProperties(userInfoToRedisMo, sysUserLogin);
        sysUser.setUserId(UserSession.getUserId());
        sysUserLogin.setUserId(UserSession.getUserId());
        sysUserMapper.updateById(sysUser);
        sysUserLoginMapper.updateById(sysUserLogin);
        putRedis();
    }

    /**
     * 注册
     *
     * @param registerJson 请求json串
     * @param request      请求
     * @throws IOException 异常
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void register(String registerJson, HttpServletRequest request) throws Exception {
        UserRegisterVO userRegisterVO = JSON.parseObject(registerJson, UserRegisterVO.class);
        UserCompanyInfo userCompanyInfo = JSON.parseObject(registerJson, UserCompanyInfo.class);
        //注册类型
        int uciCompType = userCompanyInfo.getUciCompTypeInt();
        //普通用户
        int comUserType = 4;
        String userId = UUID.randomUUID().toString().replace("-", "");
        ValidationResult result = validator.validate(userRegisterVO);
        if (result.isHashErrors()) {
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, result.getErrMsg());
        }
        //对前端传来的用户名和密码分别进行Base64解密
        String decodeUserName = AbstractEncryptUtil.decrypt(request.getHeader("userName"));
        String decodePassword = AbstractEncryptUtil.decrypt(request.getHeader("password"));
        /*
         * 用户的注册信息剥离
         */
        SysUserLogin sysUserLogin = new SysUserLogin();
        BeanUtils.copyProperties(userRegisterVO, sysUserLogin);
        sysUserLogin.setUserId(userId);
        sysUserLogin.setLoginNm(decodeUserName);
        sysUserLogin.setLoginPwd(decodePassword);
        sysUserLogin.setLoginPwdUptTime(new Date());
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(userRegisterVO, sysUser);
        sysUser.setUserId(userId);
        sysUser.setUserSex("0");
        sysUser.setUserStatus("1");
        sysUserMapper.insert(sysUser);
        sysUserLoginMapper.insert(sysUserLogin);

        /*
        当注册类型是非普通用户时，还要进行以下操作
         */
        if (uciCompType != comUserType) {
            userCompanyInfoService.add(userCompanyInfo, userId);
        }
        putRedis();
    }

    /**
     * 获取图片验证码
     *
     * @param response 返回
     */
    @Override
    public void verificationCode(HttpServletResponse response) {
        try {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            //生成验证码
            String verificationCode = VerificationCodeUtil.getStringRandom(4);
            BufferedImage img = ImageUtil.getImageFromCode(verificationCode, 100, 50, 3, true);
            ImageIO.write(img, "JPEG", out);
            Base64Encoder base64 = new Base64Encoder();
            Map<String, String> resultMap = new HashMap<>(2);
            resultMap.put("pic", base64.encode(out.toByteArray()));
            resultMap.put("code", base64.encode(verificationCode.getBytes()));
            //把四位验证码解密
            String deCode = Base64ConverterUtil.decode(base64.encode(verificationCode.getBytes()));
            ResponseUtil.showMessage("success", "请求验证码成功", resultMap);
        } catch (Exception e) {
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "验证码生成出错");
        }
    }

    /**
     * 手机号码查重+发送验证码
     *
     * @param phoneNumber 手机号码
     * @param request     请求
     * @return string
     */
    @Override
    public String checkPhoneNumber(String phoneNumber, HttpServletRequest request) {
        if (phoneNumber == null || "".equals(phoneNumber)) {
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "未输入手机号");
        }
        int checkResult = sysUserMapper.checkPhone(UserSession.getUserId(), phoneNumber);
        /*
        注释原因：测试时手机号允许重复注册，
        if (checkResult > 0) {
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "手机号已绑定用户");
        }
         */

        String phoneCodeMd5 = RandomUtil.smsCode();
        SmsSendUtil.send(null, "", UserSession.getLoginName(), phoneNumber, "SMS_190794369", new String[]{phoneCodeMd5});
        return Md5Util.stringMd5(phoneCodeMd5);
    }

    /**
     * 用户更换手机号码绑定
     *
     * @param phone   手机号码
     * @param request 请求
     */
    @Override
    public void updatePhone(String phone, HttpServletRequest request) {
        if (phone != null) {
            SysUser sysUser = sysUserMapper.selectById(UserSession.getUserId());
            if (sysUser == null) {
                throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "用户不存在");
            }
            sysUser.setUserMobile(phone);
            sysUserMapper.updateById(sysUser);
            putRedis();
        }
    }

    /**
     * 验证某个表中是否存在某字段
     *
     * @param table   表名
     * @param clo     字段名
     * @param value   待检验值
     * @param primary 主键字段名
     * @param key     主键值
     * @return int
     */
    @Override
    public int checkExist(String table, String clo, String value, String primary, String key) {
        return sysUserMapper.checkExist(table, clo, "'" + value + "'", primary, "'" + key + "'");
    }

    /**
     * 获取用户基本信息
     *
     * @param request
     * @return
     */
    @Override
    public UserInfoToRedisMO getUserInfo(HttpServletRequest request) {
        return getUserInfoFromRedis(UserSession.getUserId());
    }

    public UserInfoToRedisMO getUserInfoFromRedis(String userId) {
        Map<Object, Object> userInfoResult = redisUtil.hmget("userInfoMap");
        boolean a = redisUtil.hasKey("userInfoMap");
        if (!redisUtil.hasKey("userInfoMap") || userInfoResult.size() == 0 || userInfoResult.get(userId) == null) {
            putRedis();
        }
        return (UserInfoToRedisMO) redisUtil.hmget("userInfoMap").get(userId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addNewUser(String newUserJson, HttpServletRequest request) throws Exception {
        UserRegisterVO userRegisterVO = JSON.parseObject(newUserJson, UserRegisterVO.class);
        String userId = UUID.randomUUID().toString().replace("-", "");
        String parentId = UserSession.getUserId();
        if (parentId == null) {
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "请登录");
        }
        String uciDbid = getUserInfoFromRedis(parentId).getUciDbid();

        SysUserLogin sysUserLogin = new SysUserLogin();
        BeanUtils.copyProperties(userRegisterVO, sysUserLogin);
        sysUserLogin.setUserId(userId);
        sysUserLogin.setLoginPwd(AbstractEncryptUtil.decrypt(userRegisterVO.getLoginPwd()));
        sysUserLogin.setLoginPwdUptTime(new Date());
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(userRegisterVO, sysUser);
        sysUser.setUserId(userId);
        sysUser.setUserParentId(parentId);
        sysUserMapper.insert(sysUser);
        sysUserLoginMapper.insert(sysUserLogin);

        //绑定用户和企业信息表
        UserCompanyRela userCompanyRela = new UserCompanyRela();
        userCompanyRela.setCuDbid(UUID.randomUUID().toString().replace("-", ""));
        userCompanyRela.setUciDbid(uciDbid);
        userCompanyRela.setUserId(userId);
        userCompanyRelaMapper.insert(userCompanyRela);
        putRedis();
    }

    /**
     * 获取子用户列表
     *
     * @return
     */
    @Override
    public List<NewUserMO> getNewUserInfo() {
        return sysUserMapper.getNewUserInfo(UserSession.getUserId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateNewUser(String newUserJson, HttpServletRequest request) throws Exception {
        UserRegisterVO userRegisterVO = JSON.parseObject(newUserJson, UserRegisterVO.class);
        SysUserLogin sysUserLogin = new SysUserLogin();
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(userRegisterVO, sysUserLogin);
        BeanUtils.copyProperties(userRegisterVO, sysUser);
        sysUserLoginMapper.updateById(sysUserLogin);
        sysUserMapper.updateById(sysUser);
        putRedis();
    }

    /**
     * 删除子用户
     *
     * @param userId
     */
    @Override
    public void deleteNewUser(String userId) {
        sysUserMapper.deleteById(userId);
        sysUserLoginMapper.deleteById(userId);
        QueryWrapper<UserCompanyRela> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .eq(StringUtils.isNotEmpty(userId), "USER_ID", userId);
        userCompanyRelaMapper.delete(queryWrapper);
        putRedis();
    }

    /**
     * 获取用户性别的编码表内容
     *
     * @return
     */
    @Override
    public List<CiccLabelMO> getUserSexLabel() {
        return sysUserMapper.getUserSexLabel();
    }

    /**
     * 获取用户状态的编码表内容
     *
     * @return
     */
    @Override
    public List<CiccLabelMO> getUserStatusLabel() {
        return sysUserMapper.getUserStatusLabel();
    }

    /**
     * 获取用户状态的编码表内容
     *
     * @return
     */
    @Override
    public List<CiccLabelMO> getAccountTypeLabel() {
        return sysUserMapper.getAccountTypeLabel();
    }

    /**
     * 获取用户状态的编码表内容
     *
     * @return
     */
    @Override
    public List<CiccLabelMO> getSysStatusLabel() {
        return sysUserMapper.getSysStatusLabel();
    }
}
